﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SportsStore.Domain.Abstract;
using SportsStore.Domain.Entities;
using SportsStore.WebUI.Controllers;
using SportsStore.WebUI.HtmlHelpers;
using SportsStore.WebUI.Models;

namespace SportsStore.UnitTests
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void Can_Paginate()
        {
            //Arrange
            Mock<IProductsRepository> mock = new Mock<IProductsRepository>();
            mock.Setup(m => m.Products).Returns(new Product[] {
                new Product () { ProductID = 1, Name = "P1" },
                new Product () { ProductID = 2, Name = "P2" },
                new Product () { ProductID = 3, Name = "P3" },
                new Product () { ProductID = 4, Name = "P4" },
                new Product () { ProductID = 5, Name = "P5" }
            }.AsQueryable());

            ProductController controller = new ProductController(mock.Object);
            controller.PageSize = 3;

            //Act
            ProductListViewModel result = (ProductListViewModel)controller.List(null, 2).Model;

            //Assert
            Product[] prodArray = result.Products.ToArray();
            Assert.IsTrue(prodArray.Length == 2);
            Assert.AreEqual(prodArray[0].Name, "P4");
            Assert.AreEqual(prodArray[1].Name, "P5");
        }

        [TestMethod]
        public void Can_Generate_Page_Links()
        {
            //Arrange - define an HTML helper - we need to do this
            //in order to apply the extension method
            HtmlHelper myHelper = null;

            //Arrange - create PagingInfo data
            PagingInfo pagingInfo = new PagingInfo
            {
                CurrentPage = 2,
                TotalItems = 28,
                ItemsPerPage = 10
            };

            //Arrange
            Func<int, string> pageUrlDelegate = i => "Page" + i;

            //Act
            MvcHtmlString result = myHelper.PageLinks(pagingInfo, pageUrlDelegate);

            //Assert
            Assert.AreEqual(result.ToString(), @"<a href=""Page1"">1</a>"
                + @"<a class=""selected"" href=""Page2"">2</a>"
                + @"<a href=""Page3"">3</a>");
        }

        [TestMethod]
        public void Can_Send_Pagination_View_Model()
        { 
            //Arrange
            Mock<IProductsRepository> mock = new Mock<IProductsRepository>();
            mock.Setup(m => m.Products).Returns(new Product[] {
                new Product() { ProductID = 1, Name = "P1" },
                new Product() { ProductID = 2, Name = "P2" },
                new Product() { ProductID = 3, Name = "P3" },
                new Product() { ProductID = 4, Name = "P4" },
                new Product() { ProductID = 5, Name = "P5" },
            }.AsQueryable());

            ProductController productController = new ProductController(mock.Object);
            productController.PageSize = 3;

            //Act
            ProductListViewModel result = (ProductListViewModel)productController.List(null, 2).Model;

            //Assert
            PagingInfo pageInfo = result.PagingInfo;
            Assert.AreEqual(pageInfo.CurrentPage, 2);
            Assert.AreEqual(pageInfo.ItemsPerPage, 3);
            Assert.AreEqual(pageInfo.TotalItems, 5);
            Assert.AreEqual(pageInfo.TotalPages, 2);
        }

        [TestMethod]
        public void Can_Filter_Products()
        { 
            //Arrange - create the mock repository

            Mock<IProductsRepository> mock = new Mock<IProductsRepository>();
            mock.Setup(m => m.Products).Returns(new Product[] {
                new Product {ProductID = 1, Name = "P1", Category = "Cat1" },
                new Product {ProductID = 2, Name = "P2", Category = "Cat2" },
                new Product {ProductID = 3, Name = "P3", Category = "Cat1" },
                new Product {ProductID = 4, Name = "P4", Category = "Cat2" },
                new Product {ProductID = 5, Name = "P5", Category = "Cat3" }
            }.AsQueryable());

            //Arrange - create a controller and make the page size 3 items
            ProductController controller = new ProductController(mock.Object);
            controller.PageSize = 3;

            //Action
            Product[] result = ((ProductListViewModel)controller.List("Cat2", 1).Model).Products.ToArray();

            //Assert
            Assert.AreEqual(result.Length, 2);
            Assert.IsTrue(result[0].Name == "P2" && result[0].Category == "Cat2");
            Assert.IsTrue(result[1].Name == "P4" && result[0].Category == "Cat2");
        }

        [TestMethod]
        public void Can_Create_Categories() { 
            //Arrange - create the mock repository
            Mock<IProductsRepository> mock = new Mock<IProductsRepository>();
            mock.Setup(m => m.Products).Returns(new Product[]{
                new Product { ProductID = 1, Name = "P1", Category="Apples"},
                new Product { ProductID = 2, Name = "P2", Category="Apples"},
                new Product { ProductID = 3, Name = "P3", Category="Plums"},
                new Product { ProductID = 4, Name = "P4", Category="Oranges"},
                new Product { ProductID = 5, Name = "P5", Category="Bananas"}
            }.AsQueryable());

            //Arrange - create the controller
            NavController navController = new NavController(mock.Object);

            //Act
            string[] result = ((IEnumerable<string>)navController.Menu().Model).ToArray();

            //Assert
            Assert.AreEqual(result.Length, 4);
            Assert.AreEqual(result[0], "Apples");
            Assert.AreEqual(result[1], "Bananas");
            Assert.AreEqual(result[2], "Oranges");
            Assert.AreEqual(result[3], "Plums");
        }

        [TestMethod]
        public void Indicates_Selected_Category() 
        { 
            //Arrange create the repository
            Mock<IProductsRepository> mock = new Mock<IProductsRepository>();
            mock.Setup(r => r.Products).Returns(new Product[] {
                new Product { ProductID = 1, Name="P1", Category="Apples" },
                new Product { ProductID = 2, Name="P2", Category="Oranges" }
            }.AsQueryable());

            //Arrange create the Navcontroller
            NavController controller = new NavController(mock.Object);

            //Arrange definde the category to select
            string categoryToSelect = "Oranges";

            //Act
            string result = controller.Menu(categoryToSelect).ViewBag.SelectedCategory;

            //Assert
            Assert.AreEqual(categoryToSelect, result);
        }

        [TestMethod]
        public void Generate_Category_Specific_Product_Count() 
        {
            //Arrange create the repository
            Mock<IProductsRepository> mock = new Mock<IProductsRepository>();
            mock.Setup(r => r.Products).Returns(new Product[] {
                new Product { ProductID = 1, Name = "P1", Category = "Cat1" },
                new Product { ProductID = 2, Name = "P2", Category = "Cat2" },
                new Product { ProductID = 3, Name = "P3", Category = "Cat1" },
                new Product { ProductID = 4, Name = "P4", Category = "Cat2" },
                new Product { ProductID = 5, Name = "P5", Category = "Cat3" },
                new Product { ProductID = 6, Name = "P6", Category = "Cat1" },
                new Product { ProductID = 7, Name = "P7", Category = "Cat1" }
            }.AsQueryable());

            //Arrange create the controller
            ProductController controller = new ProductController(mock.Object);
            controller.PageSize = 3;

            //Act - test the controller for different categories
            PagingInfo result1 = ((ProductListViewModel)controller.List("Cat1").Model).PagingInfo;
            PagingInfo result2 = ((ProductListViewModel)controller.List("Cat2").Model).PagingInfo;
            PagingInfo result3 = ((ProductListViewModel)controller.List("Cat3").Model).PagingInfo;
            PagingInfo result4 = ((ProductListViewModel)controller.List(null).Model).PagingInfo;

            //Assert
            Assert.AreEqual(result1.TotalPages, 2);
            Assert.AreEqual(result2.TotalPages, 1);
            Assert.AreEqual(result3.TotalPages, 1);
            Assert.AreEqual(result4.TotalPages, 3);
            Assert.AreEqual(result1.TotalItems, 4);
            Assert.AreEqual(result2.TotalItems, 2);
            Assert.AreEqual(result3.TotalItems, 1);
            Assert.AreEqual(result4.TotalItems, 7);
        }
    }
}
